home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / tarsrc Folder / buffer.c next >
Text File  |  1993-11-27  |  10KB  |  448 lines

  1. /*
  2.  * Macintosh Tar
  3.  *
  4.  * Modified by Craig Ruff for use on the Macintosh.
  5.  */
  6. /*
  7.  * Buffer management for public domain tar.
  8.  *
  9.  * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
  10.  *
  11.  * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
  12.  *
  13.  */
  14.  
  15. #include "tar.h"
  16. #include <Devices.h>
  17.  
  18. extern OSErr    TapeOpen(Boolean noRwd, Boolean rdOnly);
  19. extern int    TapeRead(Ptr buf, int len);
  20. extern int    TapeWrite(Ptr buf, int len);
  21. extern void    TapeClose(void);
  22.  
  23. Boolean        FlushArchive();
  24.  
  25. union record    *arBlock;    /* Start of block of archive */
  26. union record    *arRecord;    /* Current record of archive */
  27. union record    *arLast;    /* Last+1 record of archive block */
  28. char        arReading;    /* 0 writing, !0 reading archive */
  29.  
  30. short        archive;
  31. HParamBlockRec    apb;        /* Archive file PB */
  32.  
  33. /*
  34.  * The record pointed to by save_rec should not be overlaid
  35.  * when reading in a new tape block.  Copy it to record_save_area first, and
  36.  * change the pointer in *save_rec to point to record_save_area.
  37.  * Saved_recno records the record number at the time of the save.
  38.  * This is used by annofile() to print the record number of a file's
  39.  * header record.
  40.  */
  41. static union record **saveRec;
  42. static union record recordSaveArea;
  43. static int        savedRecno;
  44.  
  45. /*
  46.  * Record number of the start of this block of records
  47.  */
  48. static int    baseRec;
  49.  
  50. /*
  51.  * Return the location of the next available input or output record.
  52.  */
  53. union record *
  54. FindRec()
  55. {
  56.     if (arRecord == arLast) {
  57.         if (FlushArchive())
  58.             return((union record *) nil);
  59.             
  60.         if (arRecord == arLast)
  61.             return((union record *) nil);    /* EOF */
  62.     }
  63.  
  64.     return(arRecord);
  65. }
  66.  
  67. /*
  68.  * Indicate that we have used all records up thru the argument.
  69.  * (should the arg have an off-by-1? XXX FIXME)
  70.  */
  71. void
  72. UseRec(rec)
  73. union record *rec;
  74. {
  75.     while (rec >= arRecord)
  76.         arRecord++;
  77.     /*
  78.      * Do NOT flush the archive here.  If we do, the same
  79.      * argument to userec() could mean the next record (if the
  80.      * input block is exactly one record long), which is not what
  81.      * is intended.
  82.      */
  83.     if (arRecord > arLast) {
  84.         PgmAlert("\pUseRec", "\parRecord > arLast", nil);
  85.         return;
  86.     }
  87. }
  88.  
  89. /*
  90.  * Return a pointer to the end of the current records buffer.
  91.  * All the space between findrec() and endofrecs() is available
  92.  * for filling with data, or taking data from.
  93.  */
  94. union record *
  95. EndOfRecs()
  96. {
  97.     return(arLast);
  98. }
  99.  
  100. /*
  101.  * Open an archive file.  The argument specifies whether we are
  102.  * reading or writing.
  103.  */
  104. Boolean
  105. OpenArchive(prompt, read)
  106. char    *prompt;
  107. Boolean    read;
  108. {
  109.     OSErr        err;
  110.     char        *routine = "\pOpenArchive";
  111.     Point        where;
  112.     SFReply        reply;
  113.     Str255        name;
  114.  
  115.     archive = 0;
  116.     baseRec = 0;
  117.     memset(&apb, 0, sizeof(apb));
  118.     if (pref.floppy) {
  119.         /*
  120.          * Open the floppy driver.
  121.          */
  122.         apb.fileParam.ioCompletion = nil;
  123.         apb.fileParam.ioNamePtr = "\p.Sony";
  124.         apb.fileParam.ioVRefNum = 0;
  125.         apb.fileParam.ioFVersNum = 0;
  126.         apb.fileParam.ioDirID = 0;
  127.         apb.fileParam.ioFDirIndex = 0;
  128.         apb.ioParam.ioPermssn = (read) ? fsRdPerm : fsWrPerm;
  129.         apb.ioParam.ioMisc = nil;
  130.         if ((err = PBHOpen(&apb, false)) != noErr) {
  131.             OSAlert(routine, "\pPBHOpen or PBHCreate", reply.fName, err);
  132.             return(true);
  133.         }
  134.  
  135.         if ((apb.fileParam.ioVRefNum = DoInsertFloppy()) == 0)
  136.             return(true);
  137.     
  138.     } else if (pref.tape) {
  139.         /*
  140.          * Open the tape driver.
  141.          */
  142.         if ((err = TapeOpen(false, read)) != noErr) {
  143.             OSAlert(routine, "\pTapeOpen", nil, err);
  144.             return(true);
  145.         }
  146.         
  147.     } else {
  148.         /*
  149.          * Put up a standard file dialog asking for the archive file name.
  150.          */
  151.         where.h = where.v = 75;
  152.         name[0] = 0;
  153.         if (read) {
  154.             SFGetFile(where, prompt, nil, -1, nil, nil, &reply);
  155.             
  156.         } else {
  157.             SFPutFile(where, prompt, name, nil, &reply);
  158.         }
  159.         
  160.         if (!reply.good)
  161.             return(true);
  162.         
  163.         /*
  164.          * Try and open the archive file.
  165.          */
  166.         apb.fileParam.ioCompletion = nil;
  167.         apb.fileParam.ioNamePtr = reply.fName;
  168.         apb.fileParam.ioVRefNum = reply.vRefNum;
  169.         apb.fileParam.ioFVersNum = 0;
  170.         apb.fileParam.ioDirID = 0;
  171.         apb.fileParam.ioFDirIndex = 0;
  172.         if (read) {
  173.             apb.ioParam.ioPermssn = fsRdPerm;
  174.             apb.ioParam.ioMisc = nil;
  175.             err = PBHOpen(&apb, false);
  176.     
  177.         } else {
  178.             err = PBHCreate(&apb, false);
  179.             if ((err == noErr) || (err == dupFNErr)){
  180.                 if (PBHGetFInfo(&apb, false)) {
  181.                     OSAlert(routine, "\pPBHGetFInfo", reply.fName,
  182.                             apb.fileParam.ioResult);
  183.                     return(true);
  184.                 }
  185.     
  186.                 memcpy(&apb.fileParam.ioFlFndrInfo.fdCreator, "TAR ", 4);
  187.                 memcpy(&apb.fileParam.ioFlFndrInfo.fdType, "TARF", 4);
  188.                 apb.fileParam.ioNamePtr = reply.fName;
  189.                 apb.fileParam.ioDirID = 0;
  190.                 if (PBHSetFInfo(&apb, false)) {
  191.                     OSAlert(routine, "\pPBHSetFInfo", reply.fName,
  192.                             apb.fileParam.ioResult);
  193.                     return(true);
  194.                 }
  195.     
  196.                 apb.ioParam.ioPermssn = fsWrPerm;
  197.                 apb.ioParam.ioMisc = nil;
  198.                 err = PBHOpen(&apb, false);
  199.             }
  200.         }
  201.     
  202.         if (err != noErr) {
  203.             OSAlert(routine, "\pPBHOpen or PBHCreate", reply.fName, err);
  204.             return(true);
  205.         }
  206.     
  207.         if (!read) {
  208.             apb.ioParam.ioMisc = 0;
  209.             if ((err = PBSetEOF((ParmBlkPtr) &apb, false)) != noErr) {
  210.                 OSAlert(routine, "\pPBSetEOF", reply.fName, err);
  211.                 return(true);
  212.             }
  213.         }
  214.     }
  215.     
  216.     apb.ioParam.ioPosMode = fsFromStart;
  217.     apb.ioParam.ioPosOffset = 0;
  218.     /*
  219.      * Get a block buffer for use later
  220.      */
  221.     arBlock = (union record *) NewPtr((Size) pref.blockSize);
  222.     if (arBlock == nil) {
  223.         OSAlert(routine, "\pNewPtr", "\parBlock", MemError());
  224.         if (pref.tape)
  225.             TapeClose();
  226.             
  227.         else if (!pref.floppy)
  228.             PBClose((ParmBlkPtr) &apb, false);
  229.             
  230.         return(true);
  231.     }
  232.  
  233.     arRecord = arBlock;
  234.     arLast   = arBlock + pref.blocking;
  235.     archive = apb.ioParam.ioRefNum;
  236.     arReading = read;
  237.     if (read) {
  238.         arLast = arBlock;        /* Set up for 1st block = # 0 */
  239.         FlushArchive();
  240.     }
  241.  
  242.     return(false);
  243. }
  244.  
  245. /*
  246.  * Remember a union record * as pointing to something that we
  247.  * need to keep when reading onward in the file.  Only one such
  248.  * thing can be remembered at once, and it only works when reading
  249.  * an archive.
  250.  */
  251. SaveRec(pointer)
  252. union record    **pointer;
  253. {
  254.     saveRec = pointer;
  255.     savedRecno = baseRec + arRecord - arBlock;
  256. }
  257.  
  258. /*
  259.  * Perform a write to flush the buffer.
  260.  */
  261. Boolean
  262. FlWrite()
  263. {
  264.     OSErr    err;
  265.  
  266.     if (pref.tape) {
  267.         int    n;
  268.         
  269.         n = TapeWrite(arBlock->charptr, pref.blockSize);
  270.         if (n == pref.blockSize)
  271.             return(false);
  272.             
  273.         OSAlert("\pFLWrite", "\pTapeWrite", "\pArchive write", n);
  274.         return(true);
  275.     }
  276.     
  277.     apb.ioParam.ioBuffer = arBlock->charptr;
  278.     apb.ioParam.ioReqCount = pref.blockSize;
  279.     err = PBWrite((ParmBlkPtr) &apb, false);
  280.     apb.ioParam.ioPosMode = fsAtMark;
  281.     if ((err == noErr) && (apb.ioParam.ioActCount == pref.blockSize))
  282.         return(false);
  283.         
  284.     if (
  285.         (apb.ioParam.ioActCount != pref.blockSize) ||
  286.         (err == dskFulErr)
  287.     )
  288.         DFAlert();
  289.     else
  290.         OSAlert("\pFLWrite", "\pPBWrite", "\pArchive write", err);
  291.         
  292.     return(true);
  293. }
  294.  
  295. /*
  296.  * Perform a read to flush the buffer.
  297.  */
  298. Boolean
  299. FlRead()
  300. {
  301.     OSErr    err;        /* Result from system call */
  302.     int    left;        /* Bytes left */
  303.     char    *more;        /* Pointer to next byte to read */
  304.     char    *routine = "\pFlRead";
  305.  
  306.     /*
  307.      * If we are about to wipe out a record that
  308.      * somebody needs to keep, copy it out to a holding
  309.      * area and adjust somebody's pointer to it.
  310.      */
  311.     if (saveRec &&
  312.         *saveRec >= arRecord &&
  313.         *saveRec < arLast) {
  314.         recordSaveArea = **saveRec;
  315.         *saveRec = &recordSaveArea;
  316.     }
  317.  
  318.     if (pref.tape) {
  319.         int    n;
  320.         
  321.         n = TapeRead(arBlock->charptr, pref.blockSize);
  322.         if (n == pref.blockSize)
  323.             return(false);
  324.             
  325.         if (n < 0) {
  326.             OSAlert("\pReadError", "\pTapeRead", "\pArchive read", err);
  327.             return(true);
  328.         }
  329.         
  330.         more = arBlock->charptr + n;
  331.         left = pref.blockSize - n;
  332.         apb.ioParam.ioActCount = n;
  333.  
  334.     } else {
  335.         apb.ioParam.ioBuffer = arBlock->charptr;
  336.         apb.ioParam.ioReqCount = pref.blockSize;
  337.         err = PBRead((ParmBlkPtr) &apb, false);
  338.         apb.ioParam.ioPosMode = fsAtMark;
  339.         if ((err == noErr) && (apb.ioParam.ioActCount == pref.blockSize))
  340.             return(false);
  341.     
  342.         else if ((err != noErr) && (err != eofErr)) {
  343.             OSAlert("\pReadError", "\pPBRead", "\pArchive read", err);
  344.             return(true);
  345.         }
  346.     
  347.         more = arBlock->charptr + apb.ioParam.ioActCount;
  348.         left = pref.blockSize - apb.ioParam.ioActCount;
  349.     }
  350.  
  351. again:
  352.     if (0 == (((unsigned)left) % RECORDSIZE)) {
  353.         /* FIXME, for size=0, multi vol support */
  354.         /* On the first block, warn about the problem */
  355.         if (!reblock && baseRec == 0) {
  356.             char    buf[80];
  357.  
  358.             sprintf(&buf[1], "Blocksize = %ld records",
  359.                     apb.ioParam.ioActCount / (long) RECORDSIZE);
  360.             buf[0] = strlen(&buf[1]);
  361.             PgmAlert(routine, buf, nil);
  362.         }
  363.  
  364.         arLast = arBlock + ((unsigned)(pref.blockSize - left))/RECORDSIZE;
  365.         return(false);
  366.     }
  367.  
  368.     if (reblock) {
  369.         /*
  370.          * User warned us about this.  Fix up.
  371.          */
  372.         if (left > 0) {
  373.             if (pref.tape) {
  374.                 PgmAlert(routine, "\pReblock & tape: barf!", nil);
  375.                 return(true);
  376.             }
  377.             
  378.             apb.ioParam.ioBuffer = more;
  379.             apb.ioParam.ioReqCount = left;
  380.             err = PBRead((ParmBlkPtr) &apb, false);
  381.             if ((err != noErr) && (err != eofErr)) {
  382.                 OSAlert("\pReadError", "\pPBRead",
  383.                         "\pArchive read 2", err);
  384.                 return(true);
  385.             }
  386.             
  387.             if ((apb.ioParam.ioActCount == 0) || (err == eofErr)) {
  388.                 PgmAlert(routine, "\pEof not on block boundary",
  389.                         nil);
  390.                 return(true);
  391.             }
  392.             
  393.             left -= apb.ioParam.ioActCount;
  394.             more += apb.ioParam.ioActCount;
  395.             goto again;
  396.         }
  397.         
  398.     } else {
  399.         PgmAlert(routine, "\pDid not read blocksize bytes", nil);
  400.         return(true);
  401.     }
  402. }
  403.  
  404. /*
  405.  * Flush the current buffer to/from the archive.
  406.  */
  407. Boolean
  408. FlushArchive()
  409. {
  410.     baseRec += arLast - arBlock;        /* Keep track of block #s */
  411.     arRecord = arBlock;            /* Restore pointer to start */
  412.     arLast = arBlock + pref.blocking;    /* Restore pointer to end */
  413.  
  414.     if (!arReading) 
  415.         return(FlWrite());
  416.     else
  417.         return(FlRead());
  418. }
  419.  
  420. /*
  421.  * Close the archive file.
  422.  */
  423. CloseArchive()
  424. {
  425.     ParamBlockRec    ctlpb;
  426.     
  427.     if (!arReading)
  428.         (void) FlushArchive();
  429.  
  430.     DisposPtr((Ptr) arBlock);
  431.     if (pref.floppy) {
  432.         /* Eject it! */
  433.         memset(&ctlpb, 0, sizeof(ctlpb));
  434.         ctlpb.cntrlParam.ioCompletion = nil;
  435.         ctlpb.cntrlParam.ioVRefNum = apb.ioParam.ioVRefNum;
  436.         ctlpb.cntrlParam.ioCRefNum = apb.ioParam.ioRefNum;
  437.         ctlpb.cntrlParam.csCode = 7;
  438.         (void) PBControl((ParmBlkPtr) &ctlpb, false);
  439.     
  440.     } else if (pref.tape) {
  441.         TapeClose();
  442.         
  443.     } else if (archive != 0)
  444.         (void) PBClose((ParmBlkPtr) &apb, false);
  445.  
  446.     archive = 0;
  447. }
  448.